<?php
/**
 * 
 * @author Elwin
 * @since 1.0
 */
Yii::import ( 'system.zii.widgets.grid.CGridView' );
class CDbExportGridView extends CGridView
{
	/**
	 * 判断是否初始化了Excel
	 *
	 * @var bool
	 */
	private static $_initialized = false;
	/**
	 *
	 * @var $modelClass
	 */
	public $modelClass;
	/**
	 * 导出的Excel文件名和文件类型
	 *
	 * @var array $config
	 */
	public $config = array ();
	public $stream = true;
	public static $objPHPExcel = null;
	public static $activeSheet = null;
	public $exportType = 'Excel5';
	public $columns = array ();
	/**
	 *
	 * @var $criteria
	 */
	public $criteria = array ();
	/**
	 * CGridView(array('columns'))
	 *
	 * @var array $fieldRows
	 */
	protected $fieldRows = array ();
	/**
	 * 总记录数
	 *
	 * @var $_totalItemCount
	 */
	private $_totalItemCount;
	
	/**
	 * 总页数
	 *
	 * @var $_pageCount
	 */
	private $_pageCount;
	/*
	 * 支持导出类型(Excel5,Excel2007,PDF,HTML,CSV)
	 */
	public $mimeTypes = array (
			'Excel5' => array (
					'Content-type' => 'application/vnd.ms-excel','extension' => 'xls','caption' => 'Excel(*.xls)' 
			),'Excel2007' => array (
					'Content-type' => 'application/vnd.ms-excel','extension' => 'xlsx','caption' => 'Excel(*.xlsx)' 
			),'PDF' => array (
					'Content-type' => 'application/pdf','extension' => 'pdf','caption' => 'PDF(*.pdf)' 
			),'HTML' => array (
					'Content-type' => 'text/html','extension' => 'html','caption' => 'HTML(*.html)' 
			),'CSV' => array (
					'Content-type' => 'application/csv','extension' => 'csv','caption' => 'CSV(*.csv)' 
			) 
	);
	
	/**
	 * init()方法在这里不起作用,所以使用类的构造方法
	 */
	public function __construct()
	{
		// header ( "Content-type: text/html;charset=utf-8" );
		if (! self::$_initialized)
		{
			spl_autoload_unregister ( array (
					'YiiBase','autoload' 
			) );
			include_once (Yii::app ()->basePath . DIRECTORY_SEPARATOR . 'vendors' . DIRECTORY_SEPARATOR . 'excel' . DIRECTORY_SEPARATOR . 'PHPExcel.php');
			include_once (Yii::app ()->basePath . DIRECTORY_SEPARATOR . 'vendors' . DIRECTORY_SEPARATOR . 'excel' . DIRECTORY_SEPARATOR . 'PHPExcel' . DIRECTORY_SEPARATOR . 'IOFactory.php');
			spl_autoload_register ( array (
					'YiiBase','autoload' 
			) );
			self::$_initialized = true;
			self::$objPHPExcel = new PHPExcel ();
			self::$activeSheet = self::$objPHPExcel->getActiveSheet ();
		}
	}
	/**
	 * $setting = array('filename'=>,'exprotype'=>'','sheet'=>);
	 *
	 * @param array $setting
	 */
	public function setting($setting)
	{
		foreach ( $setting as $name => $value )
			$this->$name = $value;
	}
	/**
	 * 设置导出数据字段中的model
	 *
	 * @example : explodeModels('models1,models2,...')
	 *         
	 * @param string $models
	 * @return multitype:
	 */
	public static function explodeModels($models)
	{
		$models = explode ( ',', $models );
		return $models;
	}
	
	/**
	 * 指定导出的数据表的model
	 *
	 * @param string $models 导出model的名称
	 *       
	 * @return string $text HTML选择导出字段列表
	 *        
	 * @example : models('modelA,modelB...',
	 *          array('colum1','colum2',...'alias.colum1','alias.colum2'...)
	 */
	public static function models($models, $defaultCheck = array())
	{
		$models = self::explodeModels ( $models );
		$model = new $models [0] ();
		unset ( $models [0] );
		$relations = $model->relations ();
		$checkColumns = array ();
		// echo '<pre>';
		// $model->attributeLabels ();
		foreach ( $model->attributeLabels () as $column => $lables )
		{
			// 避免有空格出现异常
			$column = trim ( $column );
			$checkColumns [$column] = $lables;
		}
		// 导出的Model
		foreach ( $models as $model => $modelName )
		{
			$model = new $modelName ();
			// 根据relations定义，得到其它model中的字段
			foreach ( $relations as $alias => $relation )
			{
				// $relation [1] Model名 $relation [2]必须定义了表与表之间的关系
				if ($modelName == $relation [1] && !empty($relation [2]))
				{
					$attributes = $model->attributeLabels ();
					foreach ( $attributes as $column => $lables )
					{
						$name = $alias . '.' . $column;
						$checkColumns [$name] = $lables;
					}
					continue;
				}
			}
		}
		// var_export($checkColumns);
		// exit();
		// 过滤掉说明重复的字段
		$checkColumns = array_unique ( $checkColumns );
		// print_r($checkColumns);
		$text = '<div><ul id="nav">';
		$text .= CHtml::checkBoxList ( 'columns', $defaultCheck, $checkColumns, array (
				'template' => '<li>{input} {label}</li>','separator' => '' 
		) );
		$text .= '</ul></div>';
		$text .= '<div id="clearfix"></div><div class="btn_common"><ul id="nav"><li id="selectall">全选</li><li id="notselectall">反选</li><li id="cancelselect">取消</li></ul></div>';
		$text .= "\n<script>
	$(function(){
	   $('#selectall').live('click', function(){				
	      $('input[type=checkbox][name^=columns]').each(function(k,v){
		   if ($(this).is(':checked')===false) $(this).attr('checked', true);				
	      });
	   });    
	   $('#notselectall').live('click', function(){				
	      $('input[type=checkbox][name^=columns]').each(function(k,v){
				$(this).attr('checked', !$(this).attr('checked'));
	      });
	   });          
       $('#cancelselect').live('click', function(){				
	      $('input[type=checkbox][name^=columns]').each(function(k,v){
		    if ($(this).is(':checked')===true) $(this).attr('checked', false);
	      });
	   });				
	});
	</script>";
		return $text;
	}
	public function checkPermission($text)
	{
		echo $text;
	}
	/*
	 * public function __set($name, $value){ $this->$name = $value; }
	 */
	
	/**
	 * 创建一个PHPExcel单例实例
	 *
	 * @return PHPExcel
	 */
	public static function createPHPExcel()
	{
		self::__construct ();
		return new PHPExcel ();
	}
	/**
	 *
	 * @param array $request 取得GET参数
	 * @param $fieldRows 将数据表转换成真实数据输出的数组
	 * @return string $modelClass
	 *        
	 * @example $fieldRows = array (
	 *     array (
	 *          'name' => 'cid','value' => 'Company::getCompanyName($data->cid,
	 *          true)'
	 *     ),
	 *     'consult.salesid',
	 *     array (
	 *          'name' => 'consult.repeat','value' => '$data->consult->repeat >
	 *          0 ? Customsult::repeatConsult($data->consult->repeat) : ""'
	 *        )
	 *     );
	 *     $exportCGrid = new CDbExportGridView ();
	 *         
	 *     $modelClass = $exportCGrid->initModel ( $_GET, $fieldRows );
	 */
	public function load($request, $fieldRows)
	{
		$models = $request ['models'];
		unset ( $request ['models'], $_GET ['r'] );
		$models = self::explodeModels ( $models );
		// 导出数据的列
		$this->columns = $request ['columns'];
		$this->modelClass = $models [0];
		$this->fieldRows = $fieldRows;
		return $this->modelClass;
	}
	/**
	 * 选择导出的字段生成Criteria
	 *
	 * @return CDbCriteria $criteria
	 *        
	 */
	public function setDbCriteria($criteria)
	{
		$select = array ();
		$with = array ();
		foreach ( $this->columns as $column )
		{
			if (strpos ( $column, '.' ) !== false)
			{
				$segs = explode ( '.', $column );
				$name = array_pop ( $segs );
				$relationame = $segs [0];
				$with [$relationame] ['select'] [] = $column;
			} else
			{
				array_push ( $select, $column );
			}
		}
		// 查询字段
		$criteria->select = $select;
		$criteria->with = $with;		
		$this->criteria = $criteria;		
		// print_r($criteria);		
		return $this->criteria;
	}
	/**
	 *
	 * @return $criteria
	 */
	public function getDbCriteria()
	{
		return $this->criteria;
	}
	
	/**
	 * 是将选择导出的字段中需要转换的列，将其处理成转换后的表达式方法
	 *
	 * @return array $columns
	 */
	public function changeColumns()
	{
		$columns = array ();
		$fieldRows = $this->fieldRows;
		if (! empty ( $this->columns ))
		{
			foreach ( $this->columns as $key => $column )
			{
				foreach ( $fieldRows as $row )
				{
					if (is_array ( $row ) && $row ['name'] == $column)
					{
						$this->columns [$key] = $row;
					}
				}
			}
		}
		return $this->columns;
	}
	
	/**
	 * 根据选择导出的字段生成的CDbCriteria,查询出结果
	 *
	 * @param $pageSize 记录数
	 *
	 * @return CActiveDataProvider $dataProvider
	 */
	public function getDataProvider($pageSize = null)
	{
		$criteria = $this->getDbCriteria ();
		if ($pageSize === null)
			$pageSize = 1;
		
		$dataProvider = new CActiveDataProvider ( $this->modelClass, array (
				'criteria' => $criteria,'pagination' => array (
						'pageSize' => $pageSize 
				) 
		) );
		// echo $this->modelClass;
		// print_r ( $criteria );
		// echo '<BR>';
		// print_r($dataProvider);
		
		// 得到查询结果总记录数
		$this->_totalItemCount = $dataProvider->getTotalItemCount ();
		// echo '<br>$this->_totalItemCount::'.$this->_totalItemCount;
		// exit ();
		$dataProvider->pagination->setItemCount ( $this->_totalItemCount );
		return $dataProvider;
	}
	
	/**
	 * 查询得到的总记录数
	 *
	 * @return integer
	 */
	public function getTotalItemCount()
	{
		return $this->_totalItemCount;
	}
	
	/**
	 * 根据总记录数和第页的记录数得到总页数
	 *
	 * @param $pageSize
	 *       
	 * @return integer
	 */
	public function getPageCount($pageSize)
	{
		return ( int ) (($this->_totalItemCount + $pageSize - 1) / $pageSize);
	}
	
	/**
	 * 数据量大，使用分批导出
	 */
	public function paginationDataProvider($page, $pageSize)
	{
		self::$objPHPExcel->createSheet ( $page );
		// self::$objPHPExcel->getActiveSheet()
		self::$objPHPExcel->setActiveSheetIndex ( $page );
		self::$activeSheet = self::$objPHPExcel->getActiveSheet ()->setTitle ( $this->filename . ($page+1) );
		// self::$activeSheet->setTitle($currentPage);		
		$this->getDataProvider ();
		$criteria = $this->getDbCriteria ();
		$pagination = new CPagination ( $this->_totalItemCount );
		// 分页导出数据
		$pagination->setCurrentPage ( $page );
		$pagination->pageSize = $pageSize;
		$pagination->applyLimit ( $criteria );
		$dataProvider = new CActiveDataProvider ( $this->modelClass, array (
				'criteria' => $criteria,'pagination' => false 
		) );
		return $dataProvider;
	}
	/**
	 *
	 * @param integer $pageSize
	 */
	public function dataWidget($pageSize)
	{
		$columns = $this->columns;
		for($page = 0; $page < $this->getPageCount ( $pageSize ); $page ++)
		{
			
			// echo '<BR><BR>$page::'.$page;
			// echo '<BR><BR>$config::';
			// print_r($config);
			
			$dataProvider = $this->paginationDataProvider ( $page, $pageSize );
			$exportGridView = $this->widget ( 'application.vendors.CDbExportGridView', array (
					'dataProvider' => $dataProvider,'columns' => $columns 
			) );
			// print_r ( $exportGridView );
			
			foreach ( $exportGridView as $model )
			{
				// echo '<BR><BR>$model:::';
				// print_r ( $model );
				// Yii::app ()->end ();
			}
			// Yii::app ()->end ();
			// $exportGridView->save($config);
		}
	}
	/**
	 *
	 * @return array
	 */
	public function getColumns()
	{
		return $this->columns;
	}
	public function __set($name, $value)
	{
		$this->$name = $value;
		// parent::__set ( $name, $value );
	}
	
	/**
	 * 设置导出的Excel的CActiveDataProvider
	 *
	 * @param CActiveDataProvider $dataProvider
	 */
	public function setDataProvider(CActiveDataProvider &$dataProvider)
	{
		$this->dataProvider = $dataProvider;
		$this->initColumns ();
	}
	
	/*
	 * 输出字段的对应的标题
	 */
	public function renderHeader()
	{
		$a = 0;
		foreach ( $this->columns as $column )
		{
			$a = $a + 1;
			if ($column instanceof CButtonColumn)
			{
				$head = $column->header;
			} else if (($column->header === null) && ($column->name !== null))
			{
				if ($column->grid->dataProvider instanceof CActiveDataProvider)
				{
					$head = $column->grid->dataProvider->model->getAttributeLabel ( $column->name );
				} else
				{
					$head = $column->name;
				}
			} else
			{
				$head = trim ( $column->header ) !== '' ? $column->header : $column->grid->blankDisplay;
			}
			// 设置Excel标题
			// $head = '设置Excel标题';
			$cell = self::$activeSheet->setCellValue ( $this->columnName ( $a ) . '1', trim ( $head ), true );
			
			/*
			 * if (is_callable ( $this->onRenderHeaderCell )) {
			 * call_user_func_array ( $this->onRenderHeaderCell, array (
			 * $cell,$head ) ); }
			 */
		}
		
		// Format the header row
		/*
		 * $header = self::$activeSheet->getStyle ( $this->columnName ( 1 ) .
		 * '1:' . $this->columnName ( $a ) . '1' ); $header->getAlignment
		 * ()->setHorizontal ( self::$horizontal_center )->setVertical (
		 * self::$vertical_center ); $header->applyFromArray (
		 * self::$headerStyle ); self::$activeSheet->getRowDimension ( 1
		 * )->setRowHeight ( $this->headerHeight );
		 */
	}
	/**
	 *
	 * @return integer $n
	 */
	public function renderBody()
	{
		// 分页限制
		/*
		 * if ($this->disablePaging) { //if needed disable paging to export all
		 * data $this->dataProvider->pagination = false; }
		 */
		$data = $this->dataProvider->getData ();
		$n = count ( $data );
		
		if ($n > 0)
		{
			for($row = 0; $row < $n; ++ $row)
			{
				$this->renderRow ( $row );
			}
		}
		return $n;
	}
	
	/**
	 * 将当前字段的值转换
	 *
	 * @param integer $row
	 */
	public function renderRow($row)
	{
		$data = $this->dataProvider->getData ();
		$a = 0;
		foreach ( $this->columns as $n => $column )
		{
			if ($column instanceof CLinkColumn)
			{
				if ($column->labelExpression !== null)
				{
					$value = $column->evaluateExpression ( $column->labelExpression, array (
							'data' => $data [$row],'row' => $row 
					) );
				} else
				{
					$value = $column->label;
				}
			} else if ($column instanceof CButtonColumn)
			{
				$value = ""; // Dont know what to do with buttons
			} else if ($column->value !== null)
			{
				$value = $this->evaluateExpression ( $column->value, array (
						'data' => $data [$row] 
				) );
			} else if ($column->name !== null)
			{
				$value = CHtml::value ( $data [$row], $column->name );
				$value = $value === null ? "" : $column->grid->getFormatter ()->format ( $value, 'raw' );
			}
			$a ++;
			/*
			 * // Check if the cell value is a number, then format it
			 * accordingly // May be improved notably by exposing the formats as
			 * public // May be usable only for French-style number formatting ?
			 * if (preg_match("/^[0-9]*\\" . $this->thousandsSeparator .
			 * "[0-9]*\\" . $this->decimalSeparator . "[0-9]*$/",
			 * strip_tags($value))) { $content =
			 * str_replace($this->decimalSeparator, '.',
			 * str_replace($this->thousandsSeparator, '', strip_tags($value)));
			 * $format = '#\.##0.00'; } else if (preg_match("/^[0-9]*\\" .
			 * $this->decimalSeparator . "[0-9]*$/", strip_tags($value))) {
			 * $content = str_replace($this->decimalSeparator, '.',
			 * strip_tags($value)); $format = '0.00'; } else if
			 * (!$this->displayZeros && ((strip_tags($value) === '0') ||
			 * (strip_tags($value) === $this->zeroPlaceholder))) { $content =
			 * $this->zeroPlaceholder;
			 * self::$activeSheet->getStyle($this->columnName($a) . ($row +
			 * 2))->getAlignment()->setHorizontal(self::$horizontal_right);
			 * $format = '0.00'; } else { $content = strip_tags($value); $format
			 * = null; }
			 */
			// echo '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;' . $value;
			//
			// $cell = self::$activeSheet->setCellValue($this->columnName($a) .
			// ($row + 2), $content, true);
			// $value 某个字段的值
			$cell = self::$activeSheet->setCellValue ( $this->columnName ( $a ) . ($row + 2), $value, true );
			/*
			 * // Format each cell's number - if any if (!is_null($format)) {
			 * self::$summableColumns[$a] = $a;
			 * self::$activeSheet->getStyle($this->columnName($a) . ($row +
			 * 2))->getNumberFormat()->setFormatCode($format); }
			 * if(is_callable($this->onRenderDataCell)) {
			 * call_user_func_array($this->onRenderDataCell, array($cell,
			 * $data[$row], $value)); }
			 */
		}
		/*
		 * // Format the row globally $renderedRow =
		 * self::$activeSheet->getStyle('A' . ($row + 2) . ':' .
		 * $this->columnName($a) . ($row + 2));
		 * $renderedRow->getAlignment()->setVertical(self::$vertical_center);
		 * $renderedRow->applyFromArray(self::$style);
		 * self::$activeSheet->getRowDimension($row +
		 * 2)->setRowHeight($this->rowHeight);
		 */
	}
	
	/**
	 * Loads Excel file as a template for report
	 */
	public function loadTemplate($template = '')
	{
		if ($template != '')
			$this->_template = $template;
		
		if (! is_file ( $this->_templatePath . $this->_template ))
			throw new Exception ( 'Unable to load template file: ' . $this->_templatePath . $this->_template );
			
			// identify type of template file
		$inputFileType = PHPExcel_IOFactory::identify ( $this->_templatePath . $this->_template );
		// TODO: better control of allowed input types
		// load template file into PHPExcel objects
		$this->objReader = PHPExcel_IOFactory::createReader ( $inputFileType );
		$this->objPHPExcel = $this->objReader->load ( $this->_templatePath . $this->_template );
		$this->objWorksheet = $this->objPHPExcel->getActiveSheet ();
		
		$this->_usingTemplate = true;
	}
	/**
	 * 产生Excel列的标识(A1,B1...AA1,AB1...AA2,AB2...)
	 *
	 * @param int $index
	 * @throws Exception
	 * @return string
	 */
	public function columnName($index)
	{
		-- $index;
		if (($index >= 0) && ($index < 26))
		{
			return chr ( ord ( 'A' ) + $index );
		} else if ($index > 25)
		{
			return ($this->columnName ( $index / 26 )) . ($this->columnName ( $index % 26 + 1 ));
		} else
		{
			throw new Exception ( "Invalid Column # " . ($index + 1) );
		}
	}
	
	/**
	 * 执行导出Excel
	 *
	 * (non-PHPdoc)
	 *
	 * @see CBaseListView::run()
	 */
	public function run()
	{
		// print_r($this);
		// exit();
		$this->cleanOutput ();
		// header ( 'Content-Type:application/csv;charset=UTF-8' );
		// exit('dd');
		$this->renderHeader ();
		$row = $this->renderBody ();
		// $this->renderFooter($row);
	}
	/**
	 *
	 * @param array $config
	 */
	public function save($config = '')
	{
		/*
		 * if (empty ( $config )) $config = $this->config; if ($config ['type'])
		 * { $this->exportType = $config ['type']; } $config = array (
		 * 'filename' => '导出' . date ( 'Y-m-d H:i:s' ),'type' => 'Excel5' );
		 */
		header ( 'Cache-Control: must-revalidate,post-check=0, pre-check=0' );
		header ( 'Cache-Control: max-age=0' );
		// header ( 'Content-Transfer-Encoding:binary' );
		header ( 'Pragma: public' );
		header ( 'Content-type:' . $this->mimeTypes [$this->exportType] ['Content-type'] );
		header ( 'Content-Disposition: attachment; filename="' . $this->filename .date('Y-m-d'). '.' . $this->mimeTypes [$this->exportType] ['extension'] . '"' );
		
		$objWriter = PHPExcel_IOFactory::createWriter ( self::$objPHPExcel, $this->exportType );
		if (! $this->stream)
		{
			$objWriter->save ( $this->filename );
		} else
		{
			// $this->filename = $config['filename'];
			// output to browser
			// if(!$this->filename) {
			// $this->filename = $this->title;
			// }
			// set CSV file to UTF-8
			// $objWriter->setUseBOM ( true );
			$objWriter->save ( 'php://output' );
		}
	}
	
	/**
	 * Performs cleaning on mutliple levels.
	 *
	 * From le_top @ yiiframework.com
	 */
	private static function cleanOutput()
	{
		for($level = ob_get_level (); $level > 0; -- $level)
		{
			@ob_end_clean ();
		}
	}
	/**
	 * 返回Yii自动加载方法
	 */
	public function __destruct()
	{
		spl_autoload_register ( array (
				'YiiBase','autoload' 
		) );
	}
}
?>